home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 4 / Apprentice-Release4.iso / Languages / Mops 2.7 / Mops ƒ / Class < prev    next >
Text File  |  1995-12-05  |  65KB  |  2,481 lines

  1. \ High-level class/object implementation.
  2.  
  3. cr .( loading Class...)
  4.  
  5. \ Note that the object header format is documented at "object building"
  6. \ below.
  7.  
  8. \ June 91    mrh    Moved indexed methods from Object to Indexed-obj in Struct.
  9. \                Added BIND_WITH.
  10. \ May 92    mrh    Added [] as synonym for **
  11. \ Apr 94    mrh    (Mops 2.5) Added several features:
  12. \                Naming of ivars pushing their address.
  13. \                Temp (local) objects
  14. \                record{ ... } replacing general/non-general distinction.
  15. \                classinit: now sent to all superclasses.
  16. \                msg: super> aSuper
  17. \ Feb 95    mrh    Added static and public ivars.
  18. \ Apr 95    mrh    Allowed static ivars to also be public.  Added class_as>.
  19.  
  20. \ You want documentation?  Here you are!!
  21.  
  22. \ Here are all our various class/object formats:
  23.  
  24.  
  25.  
  26. (*            ================= Object header ======================
  27.  
  28. Note if the obj is an ivar, it doesn't have a header if it's in a record,
  29. unless the ivar is indexed.  Indexed ivars always have headers, no matter
  30. what, since the indexing code relies on it.
  31.  
  32.  
  33. 2 bytes        Offset to the indexed area, rel to the class pointer
  34.             (which follows).  If not indexed, this will be 6.
  35.  
  36. 4 bytes        Class pointer (relocatable).
  37.  
  38. 2 bytes        Offset from the data start to the class pointer.
  39.             For simple objects (i.e. not embedded), this is -6.
  40.             For embedded objects, it will be more negative.  Note it
  41.             will always be negative.
  42.  
  43. (object's data starts here)
  44.  
  45. For indexed objects, the indexed area (after the ivars) is preceded by
  46. the indexed descriptor (xdesc) with this format:
  47.  
  48. 2 bytes        Width of indexed elements (in bytes)
  49. 4 bytes        Number of elements minus 1 (i.e. LIMIT-1).
  50.             The low word of this is used by a CHK instruction
  51.             if #elements is < 32K.
  52.  
  53. If indexing is attempted on a non-indexed object, the "offset to the
  54. indexed area" will be 6, taking us to the beginning of the object's
  55. data.  The CHK instruction will be done at offset -2 from there, which
  56. won't be the #elements, of course, but will be the offset to the
  57. class pointer WHICH IS ALWAYS NEGATIVE!!  Thus the CHK will always fail!
  58. This was a deliberate trick - about the only place in Mops I've
  59. resorted to anything like this, you'll be glad to know.
  60.  
  61.  
  62.         ==============  Class dictionary entry  ================
  63.  
  64. link/name        as for normal words
  65. 4 bytes            call to BLD - the word which builds an object
  66. 4 bytes            link to methods chain (relative)
  67. 4 bytes            link to ivar chain (relative)
  68. 2 bytes            non-indexed data length
  69. 2 bytes            width of indexed elements, or zero if not indexed
  70. 2 bytes            flags
  71. 4(n+1) bytes    N-way to superclasses (n relocatable addrs terminated by zero)
  72.  
  73. Flag bits:
  74. bit 0            "large" - indexed with > 64K elements.
  75. bit 1            class is exported from a module
  76.  
  77.  
  78.         ==============  ivar dictionary entry  ================
  79.  
  80. 4 bytes        hashed name
  81. 4 bytes        link to prev ivar dic entry (relative addr)
  82. 4 bytes        class pointer (relocatable)
  83. 2 bytes        offset of this ivar's data from the base addr of the class
  84. 2 bytes        number of elements if indexed, or zero if not
  85. 2 bytes        flags
  86.  
  87. Flag bits: (zero is rightmost - what will we do on PowerPC?)
  88.  
  89. bit 0        1 = ivar gets an object header
  90. bit 1        1 = this is a static ivar
  91. bit 2        1 = this is a public ivar
  92.  
  93. Note: although indexed objects can have 2^^32 elements, we are
  94. assuming that an ivar can't have more than 64K elements.  This is
  95. because we are limiting the maximum ivar length of a class to 64K bytes,
  96. which is a stricter condition.  Would anybody want a longer ivar than
  97. this??
  98.  
  99.         ==============  Method dictionary entry  ================
  100.  
  101. 4 bytes        hashed name
  102. 4 bytes        link to prev method dic entry (relative addr)
  103. 2 bytes        flags
  104.  
  105. Flag bits:
  106.  
  107. bit 0        1 = private method (note other way round to ivars - we're using
  108.                 1 for the unusual case)
  109. bit 7        1 = there's a callFirst and/or callLast method
  110.  
  111.  
  112.         ==========================================================
  113. *)
  114.  
  115.  
  116. : xx  db ;            \ useful!
  117.  
  118.     0    value    PUB/PRIV    \ -1 private, 1 public, 0 default - for ivars and methods
  119. false    value    STATIC?        \ true if following ivars are to be static
  120.     0    value    ^CLASS        \ addr of the class we're currently compiling
  121.     0    value    PIVAR        \ hashed name of any public ivar we're accessing
  122.     0    value    PIVSEL        \ hashed selector of any msg being sent to
  123.                             \  to a public ivar
  124.  
  125.     0    value    NEWOBJECT    \ addr of object being created
  126.     0    value    #SUP        \ number of superclasses for current class
  127.     0    value    SUPERS_TO_SKIP
  128.     0    value    INITID
  129.  
  130.  
  131. \                ===============================
  132.  
  133. \                        UTILITY WORDS
  134.  
  135. \                ===============================
  136.  
  137. : PRIVATE        -1 -> pub/priv  ;        \ following methods and ivars will be private
  138. : PUBLIC         1 -> pub/priv  ;        \ following methods and ivars will be public
  139.  
  140. : END_PRIVATE    0 -> pub/priv  ;        \ back to the default
  141. : END_PUBLIC    0 -> pub/priv  ;        \ ditto
  142.  
  143.  
  144. : X    bld  123  ;                \ The 123 blocks optimization!
  145.  
  146. ' x @  forget x      constant    CLASSMK        \  JSR  bldVec-base(A3)
  147.  
  148. : EXBASE    $ 4E92  w,  ;    immediate    \  JSR  (A2)
  149.  
  150. : >OBJ  ( cfa -- ^obj )  inline{ 8 +}  8 +  ;
  151. : OBJ>  ( ^obj -- cfa )  inline{ 8 -}  8 -  ;
  152.             \ Note: we don't use >class here, since obj> shouldn't be
  153.             \ used for embedded objects, and it is used during obj
  154.             \ building when the ^class isn't there yet.
  155.  
  156. : CHKCLASS    \ ( cfa -- cfa )
  157.     class?  ?EXIT
  158.     .id  space  true ?error 80  ;
  159.  
  160. : ?>CLASS   ( ^obj -- ^class )
  161.     >class  dup 0= ?error 81  ;        \ If no legal class ptr, probably
  162.                                     \ not an obj addr at all!
  163.  
  164. \ the following offsets refer to where a ^class points, i.e. the cfa
  165. \ of the class.
  166.  
  167. : MFA    inline{ 4 +}    4 +  ;        \ Methods link
  168. : IFA    inline{ 8 +}    8 +  ;        \ ivar link
  169. : DFA    inline{ 12 +}  12 +  ;        \ Data len (2 bytes),
  170.                                     \  width of indexed elts (2 bytes)
  171. : FFA    inline{ 16 +}  16 +  ;        \ Flags
  172. : SFA    inline{ 18 +}  18 +  ;        \ Superclass N-way pointer
  173.  
  174. : GETDLEN        \ ( ^obj -- n )  Gets length of object's named ivars
  175.     ?>class dfa w@  ;
  176.  
  177. : (^DLEN)    \ ( ^obj -- ^datalen )  This is a low-level word which should
  178.             \  normally only be used in the Mops system stuff.  Note it
  179.             \  takes ^obj, not ^class, and it doesn't do a module check
  180.             \  - it assumes the class is in the same segment as the object.
  181.     ?>class dfa  ;
  182.  
  183. : DLEN&XWID        \ ( ^class -- dlen xwid )
  184.     ?>classInMod
  185.     dfa dup  w@  swap  2+ w@
  186.     ?unHoldMod  ;
  187.  
  188. : DLEN    dlen&xwid  drop  ;
  189. : XWID    dlen&xwid  nip   ;
  190.  
  191. : IVARLEN    postpone dlen  ;    immediate        \ an alias for dlen
  192.  
  193. : ?>MAINDIC  { ^class -- '^class }
  194.         \ If ^class is exported from a module, we return the main dic
  195.         \ equivalent.  If it's not exported, we return it unchanged.
  196.         \ We need this word since for exported classes, we need to use the
  197.         \ imported address (in the main dictionary) as the class pointer
  198.         \ in a new object or an ivar dic entry (so that the module will be
  199.         \ invoked properly when a method is sent to the object.
  200.  
  201.     ^class ffa 1+ 1 btest
  202.     IF        ^class >name n>count sfind drop
  203.     ELSE    ^class
  204.     THEN  ;
  205.  
  206.  
  207. : FINDM  { selID ^cl -- offs cfa }        \ Finds a method in a class.
  208.     ^cl ?>classInMod -> ^cl
  209.     ^cl -> objClass
  210.     selID ^cl 4 (findm)
  211.     NIF  cr  ^cl .id  108 die  ( method not found )  THEN  ;
  212.  
  213.  
  214. : IVFINDM    \ ( selID ^ivar -- cfa base-offs )
  215.             \  Looks for a method in an ivar.
  216.             \  Note we return the results the other way around to
  217.             \  objFindM, since this is what we usually want here.
  218.     8 + @abs ( addr of ivar's class )  findm  swap  ;
  219.  
  220.  
  221. : SEND  { ^obj selID \ svMB -- }    \  Executes a method given its sel ID.  Used in
  222.                                     \      late binding.  Can also be used if you
  223.                                     \   have a dynamically determined method ID.
  224.     modBase -> svMB
  225.     selID ^obj  objFindM  ex-method
  226.     svMB -> modBase  ;
  227.  
  228.  
  229. : (DEFER)  ( ^obj -- )        \ Looks up SelID at IP and runs the method.
  230.                             \  Used in late binding.
  231.     @(ip)  send  ;
  232.  
  233.  
  234. 0 -> quitvec   0 -> abortvec   0 -> objInit        \ clear vectors
  235. ' pfind  -> ufind
  236.  
  237.  
  238. : ?CLASS        \ Error if not compiling a class definition.
  239.     cstate 0=  ?error 115  ;
  240.  
  241.  
  242. \ IVFIND is called when we've parsed a selector.  It determines if the next
  243. \ word is an ivar.
  244. \ Note: if found, (findm) returns the equivalent of the cfa of
  245. \ a method, which for ivars, is the addr of the class pointer.
  246.  
  247. : IVFIND    \ ( str-addr -- offs ^ivar T  |  -- str-addr F )
  248.     cstate  NIF  false  EXIT  THEN
  249.     hash
  250.     ^class  8  (findm)
  251.     IF  8 -  true  ELSE  here false  THEN  ;
  252.  
  253.  
  254. \ TOfind looks for a temp (local) object.
  255.  
  256. : TOfind    \ ( str-addr -- cfa T  |  -- str-addr F )
  257.     tmpObjs  NIF  false  EXIT  THEN
  258.     hash
  259.     tmpObjs  8  (findm)
  260.     IF  8 -  true  ELSE  here  false  THEN  ;
  261.  
  262.  
  263. (*
  264. LocFind will be called from Ufind, which is the vector that gets first
  265. shot at recognizing a word.
  266. It looks at all the possibilities involving local names, which are
  267. not in the regular dictionary.  These possibilities are: named parms/locals,
  268. local objects, and if a class is being compiled, ivars of this class.
  269.  
  270. In the latter case, we arrange for the ivar's address to
  271. be pushed at run time simply by compiling ^base followed by an add of the
  272. ivar's offset - our code generation will produce optimal code for this.
  273. We then have to return the xt of some word to keep FIND happy - we don't
  274. need to compile anything else, so we use the xt of NULL and return a 1
  275. instead of True - this makes FIND think it's immediate.  So NULL is
  276. executed immediately, which does precisely nothing.
  277.  
  278. The one exception to this is if the "ivar" turns out to be SELF or SUPER
  279. - in this case we need to call the nucleus word SELF which works out
  280. the right base address (this is what happened pre-2.5).  Here we keep
  281. FIND happy by pushing the xt of SELF and True, so that it sees we've
  282. found SELF.
  283. *)
  284.  
  285. : LocFind        \ ( str-addr -- cfa T  |  -- str-addr F )
  286.     Pfind    ?dup  ?EXIT                    \ Found a named parm/local
  287.     TOfind
  288.     IF                                    \ Found temp obj
  289.         drop                            \ Don't need its dic addr
  290.         postpone locReg  postpone literal  postpone +
  291.         ['] null  1   EXIT
  292.     THEN
  293.  
  294. \ Now we look for an ivar name
  295.  
  296.     cstate  NIF  false  EXIT  THEN        \ search fails if we're not compiling
  297.                                         \  a class
  298.     dup hash ^class  8  (findm)
  299.     IF                                    \ Found ivar
  300.         drop nip                        \ Don't need its dic addr or str addr
  301.         dup $ FFFE >=                    \ is it SELF or SUPER ?
  302.         IF    drop  ['] self  true  EXIT
  303.         THEN
  304.         postpone ^base postpone literal  postpone +
  305.         ['] null  1
  306.     ELSE    false
  307.     THEN  ;
  308.  
  309.  
  310. : ILFA     ( infa -- ilfa )    4+  ;
  311.  
  312.  
  313. : ^ICLASS  ( infa -- ^class | 0 )
  314.     8 + dup @ NIF   drop 0   ELSE   @abs ?>classInMod   THEN  ;
  315.  
  316.  
  317. : IOFFS    ( infa -- ioffs )    12 + w@  ;
  318. : I#ELS    ( infa -- #els )    14 + w@  ;
  319. : IFFA     ( infa -- iffa )    inline{ 16 +}  ;
  320.  
  321.  
  322. : LASTIVAR?        \ ( infa -- infa b )  True if nfa is super or self.
  323.                 \ These are distinguished by having an "offset" of
  324.                 \ $ FFFE and $ FFFF respectively.
  325.     dup @ 0> IF  false  EXIT  THEN
  326.                 \ If there's an Nway for superclasses there, then it can't
  327.                 \  be super or self.
  328.     dup 12 + w@ $ FFFE >=  ;
  329.                 \ Otherwise it's a normal ivar dic entry, so we grab the
  330.                 \  offset field and test it.
  331.  
  332.  
  333. : ^NEXTIVAR    \ ( infa -- infa' )
  334.     ilfa  displace  ;
  335.  
  336.  
  337. forward INITIVAR      \ Performs the classinit: method on the ivar on the stack
  338.  
  339.  
  340. \                        ========================
  341.  
  342. \                                BINDING
  343.  
  344. \                        ========================
  345.  
  346.     0    value    OBJ_BASE
  347.     0    value    OBJ_DISPL
  348.     0    value    OBJ_LOCAL_DISPL
  349.     0    value    OBJ_IND
  350.  
  351. false    value    SELF?
  352.  
  353.  
  354. : OBJ        \ Called from within an inline method.  Passes the object's
  355.             \  base and displacement to Handlers to generate the correct
  356.             \  address.  Optimization will then apply.
  357.  
  358.     obj_base obj_displ
  359.     obj_ind  genaddr
  360.     obj_local_displ  postpone literal  postpone +  ;        immediate
  361.  
  362.  
  363. : IX        \ Also called from within an inline method.
  364.             \ Compiles code to generate the indexed address.
  365.     ^class  dlen&xwid  swap
  366.     self?
  367.     IF  drop  -1  ELSE  6 +  THEN
  368.     obj_base obj_displ  obj_local_displ  obj_ind  ^class ffa w@
  369.     genxaddr  ;            immediate
  370.  
  371.  
  372. local  EARLY_BIND  { oCfa oBase oDispl oLDispl oind slf? -- }
  373.  
  374.  
  375. : INL_BIND    \ ( -- b )
  376.     \ In-line code to be compiled for this method.
  377.     \ But note, we don't do it if obj_base is zero, meaning that
  378.     \ we have put the ^obj in A0 as a temporary.  Some inline
  379.     \ methods could cause a clash on A0.  So in this case we
  380.     \ call the out-of-line code - we return true so that this
  381.     \ will be done by NORM_BIND.  Otherwise we return false.
  382.  
  383.     obj_base
  384.     NIF                                    \ Update cfa to the out-of-line code
  385.         oCfa 2+ dup c@ + aligned  -> oCfa  true
  386.     ELSE
  387.         ^class  cstate  self?                \ Save over upcoming evaluate
  388.         slf? NIF  objClass -> ^class  THEN    \ Set ^class and cstate
  389.         true -> cstate                        \  so ivars are accessible
  390.         slf? -> self?
  391.         oCfa  (compinl)
  392.         -> self?  -> cstate  -> ^class        \ Restore
  393.         false
  394.     THEN  ;
  395.  
  396.  
  397. : NORM_BIND
  398.     oCfa  postpone obj  EB  ;
  399.  
  400.  
  401. :loc  EARLY_BIND        \ { oCfa oBase oDispl oLDispl oind slf? -- }
  402.     obj_base  obj_displ  obj_local_displ  obj_ind        \ Save
  403.     oBase    -> obj_base            oDispl    -> obj_displ
  404.     OLdispl    -> obj_local_displ    oind    -> obj_ind
  405.     oCfa w@  inlMk =
  406.     IF  inl_bind  ELSE  true  THEN
  407.     IF  norm_bind  THEN
  408.     -> obj_ind  -> obj_local_displ
  409.     -> obj_displ  -> obj_base                            \ Restore
  410. ;loc
  411.  
  412.  
  413. : BIND_TO_OBJ        \ ( cfa ^obj -- )
  414.     -1 swap  0  0  false  early_bind  ;
  415.  
  416. : BIND_TO_STK        \ ( cfa -- )
  417.     stkObj  0 swap  false  early_bind  ;
  418.  
  419. : BIND_TO_IVAR  { cfa offs -- }
  420.     cfa  obj_base  obj_displ
  421.     obj_local_displ offs +
  422.     obj_ind  false  early_bind  ;
  423.  
  424. : BIND_TO_TMPOBJ  { cfa offs -- }
  425.     cfa  4  offs
  426.     0 0 false  early_bind  ;
  427.  
  428. : BIND_TO_SELF  { cfa offs -- }
  429.     cfa  obj_base  obj_displ  offs  obj_ind  true  early_bind  ;
  430.  
  431.  
  432. \                    ===========================
  433.  
  434. \                     INITIALIZING NEW OBJECTS
  435.  
  436. \                    ===========================
  437.  
  438.     0    value    ^XDESC        \ Used in the setting up of an index descriptor
  439.     0    value    OFFS        \ Used in setting up ivars
  440. false    value    REC?        \ Are we compiling a record?
  441. false    value    UNION?        \ Are we compiling a union in a record?
  442.     0    value    UNIONOFFS    \ Base offset of the current union
  443.  
  444.  
  445. : ?HDRS  { thisClass ^data infa \ xw flags -- }
  446.         \ For normal ivars, this word sets up the object headers - namely
  447.         \ ^class, ^class offset, xoffs and xdesc.  But if we're in a record,
  448.         \ non-indexed ivars don't have an object header.
  449.         
  450.     thisClass  0EXIT            \ out if self or super
  451.     infa iffa w@  -> flags
  452.     flags 1 and  0EXIT            \ out if ivar not flagged as needing a header
  453.     flags 2 and  ?EXIT            \ out if it's static (doesn't live in the
  454.                                 \  object at all)
  455.  
  456. \ OK, we need the headers.  Let's set 'em up:
  457.  
  458.     thisClass ?>maindic
  459.     false -> relocChk?
  460.             ^data 6 -  reloc!        \ ^class (safe if outside a module
  461.     true  -> relocChk?                \  here, since ivars of an obj belonging
  462.                                     \  to an exported class can only be
  463.                                     \  accessed while the module is running)
  464.  
  465.     -6        ^data 2-   w!            \ ^class offset
  466.     thisClass xwid -> xw
  467.     xw  NIF                           \ Not indexed:  store dummy xoffs
  468.         6    ^data 8 -  w!  EXIT        \  and we're done.
  469.     THEN
  470.     thisClass dlen aligned            \ Indexed:
  471.     dup  12 +    ^data 8 -    w!            \ xoffs
  472.                 ^data +  -> ^xdesc
  473.     xw                ^xdesc        w!        \ xdesc
  474.     infa i#els  1-    ^xdesc 2+    !  ;    \ #elements
  475.  
  476.  
  477. forward    IVSETUP
  478.  
  479. : NW_IVSETUP  { ^nway boffs EOoffs
  480.                 \ initEOoffs svHeldMod thisClass ^slf totalOffs -- }
  481.  
  482. \ Sets up the groups of ivars for each superclass, for a multiply inherited
  483. \ object.  Each group we call an "embedded object", which sort of describes
  484. \ what it is.
  485. \ ^nway points to the current superclass pointer in the n-way defining the
  486. \ multiple inheritance.  boffs is the base offset from newObject, the actual
  487. \ top-level (non-ivar) object being created.  EOoffs is the extra offset to
  488. \ the current embedded object.  When an embedded object starts at a non-zero
  489. \ EOoffs, we put in front of it a 2-byte offset to the class pointer.  Note
  490. \ that if the multiply inherited object is an ivar, there may not be a class
  491. \ pointer!  This doesn't matter, since it's better for multiply inherited
  492. \ objects to always have the same format, wherever they are, and any attempt
  493. \ to use the class pointer offset to get the (nonexistent) class pointer
  494. \ will most probably be caught by our checks.
  495.  
  496. \ With Mops 2.5 we're now sending classinit: separately to each superclass.
  497.  
  498.     EOoffs -> initEOoffs
  499.     BEGIN
  500.         ^nway @abs ?>classInMod  -> thisClass    \ may hold a mod
  501.         boffs EOoffs + initEOoffs -  -> totalOffs
  502.         thisClass ifa displace  totalOffs  EOoffs  ivSetup
  503.         
  504.     \ now we send Classinit:
  505.         thisClass -> objClass
  506.         initID  thisClass  4  (findm)              \ ( -- offs cfa T  |  F )
  507.         IF    swap newObject +  totalOffs +  swap  ex-method  THEN
  508.         ?unholdMod                                \ now finished with the mod
  509.         1cell ++> ^nway
  510.         ^nway @
  511.     WHILE        \ another class coming up - store 2-byte ^class offset first
  512.         thisClass dlen  ++> EOoffs
  513.         EOoffs aligned  -> EOoffs
  514.         EOoffs negate 8 -            \ ^class offset for store
  515.         EOoffs initEOoffs -            \ offset not already included in boffs
  516.         boffs + newObject +            \ final addr for store
  517.         w!
  518.         2 ++> EOoffs
  519.     REPEAT  ;
  520.  
  521.  
  522. :f  IVSETUP  { infa boffs EOoffs \ svHeldMod thisClass ^data -- }
  523.  
  524. \ Recursively traverses the tree of nested ivar definitions in a class,
  525. \ building the necessary ^class offsets and indexed area headers.
  526. \ infa is the nfa of the current ivar, and boffs is the current base offset
  527. \ for ivars at this point in the nested ivar structure, relative to newObject,
  528. \ the current top-level object being created.
  529.  
  530. \ When this word is called, if thisClass is in a module, the module will
  531. \ be held.  In some circumstances the caller still needs it.  The
  532. \ recursive call might require another module to be held, so we have to
  533. \ save and restore any module held on entry.
  534.  
  535.     heldMod -> svHeldMod                \ save heldMod
  536.     0 -> heldMod                        \ clear it so nobody can unhold
  537.     BEGIN
  538.         infa @ 0>
  539.         IF                                \ we've hit a superclass n-way
  540.             infa boffs EOoffs NW_ivSetup    \ set up superclasses
  541.             svHeldMod -> heldMod  EXIT    \ restore heldMod, and out
  542.         THEN
  543.         infa lastivar? nip
  544.         IF                                \ no more ivars
  545.             svHeldMod -> heldMod  EXIT    \ restore heldMod, and out
  546.         THEN
  547.  
  548.         infa iffa w@ 2 and                \ static ivars don't live in the object
  549.         NIF
  550.             infa ^iclass  -> thisClass        \ may hold another mod
  551.             infa ioffs  -> offs                \ relative offs of this ivar
  552.             boffs offs +  newObject +  -> ^data
  553.         
  554.         \ First we do a recursive call to set up the
  555.         \ (nested) ivars of this ivar's class.
  556.     
  557.             ?Rdepth                            \ Check on recursion depth
  558.             infa  ^iclass  ifa  displace    \ infa of last nested ivar
  559.             ( newNfa )  offs boffs +        \ New base offset
  560.             0
  561.             ivSetup                            \ Recursive call to set up this ivar
  562.             ?unHoldMod                        \ unhold any held mod
  563.             thisClass ^data infa  ?hdrs        \ Add headers if nec
  564.             boffs infa  initivar            \ Initialize by calling Classinit:
  565.         THEN
  566.         infa ^nextivar  -> infa                \ Step to next ivar and loop.
  567.     AGAIN  ;f
  568.  
  569.  
  570. forward  CLASSINIT        \ Will be  classinit: newObject - once we can send
  571.                         \  messages
  572.  
  573.  
  574. \ HASHED-HDR lays down the dic header for an ivar or method.
  575. \ The format is:
  576. \
  577. \ 4 bytes        hash
  578. \ 4 bytes        link (self-relative addr of prev entry)
  579. \
  580. \ This entry has to become the first on the chain, so we pass in the
  581. \ addr of the chain header.
  582.  
  583. : HASHED-HDR        \ ( chain-hdr hash-val -- )
  584.     ,                        \ comma in hash value
  585.     dup displace            \ get abs addr of prev entry
  586.     displ,                    \ comma it in as self-relative addr
  587.     here 8 -  swap  displ!    \ update chain header
  588. ;
  589.  
  590.  
  591. forward    DIC-OBJ
  592.  
  593. : IVDEF  ( #els ) { iclass \ #els wid siz clOffs flags -- }
  594.         \ Compiles an ivar dictionary entry.  If indexed, must have
  595.         \ < 64K elements.  iclass is the ivar's class.  The class of
  596.         \ which this is an ivar, is pointed to by ^class.
  597.  
  598.     pub/priv 1 =  4 and -> flags    \ initial flags - set bit 2 if we're public
  599.     Mword
  600.     ivFind  ?error 117                \ same name as another ivar
  601.     drop
  602.     iclass xwid  -> wid                \ indexed width of ivar class
  603.     iclass dlen  -> siz                \ non-indexed size of this ivar
  604.     
  605. \ The initial offset is the current dlen of the class.
  606.  
  607.     ^class dfa w@  -> clOffs
  608.     
  609.     ^class  ifa
  610.     here  hash  hashed-hdr            \ dic header for ivar
  611.  
  612.     iclass ?>mainDic  reloc,
  613.     
  614. \ Now we need to comma in the 2-byte offset to the ivar within
  615. \ the class.  First we need to make some adjustments...
  616. \ Do we need to align the offset:
  617.  
  618.     siz 1 >                \ we do if the ivar size is longer than 1
  619.     wid rec? not and    \ or if it's indexed, and we're not in a record
  620.     or
  621.     IF                \ We do need to align the offset. Note that if the
  622.                     \ ivar class is multiply inherited with >1 superclass
  623.                     \ of non-zero length, the ivar size will always be >1.
  624.         clOffs aligned  -> clOffs
  625.     THEN
  626.  
  627.     iclass ffa 1+ 2 btest    \ general?
  628.     dup IF  union? ?error 190  THEN
  629.                             \ can't have a general object in a union
  630.     rec? not or                \ or not in a record?
  631.     IF                        \ Yes.  In this case the ivar will have
  632.                             \  the standard 8-byte object header. So its data
  633.         8 ++> clOffs        \  will start 8 bytes later than otherwise.
  634.         1 or> flags            \ and we'll mark this in the ivar flags
  635.                             \  so ?hdrs will do the right thing.
  636.     THEN
  637.     clOffs  w,
  638.  
  639.     wid
  640.     IF                \ Indexed. Stack has #els.  We calculate the indexed
  641.                     \ length of this ivar and increment clOffs.
  642.                     \ If we're not in a record, we also need to align the
  643.                     \ non-indexed size of the ivar, since the xdesc must
  644.                     \ be aligned. (If we're in a record, there won't be an
  645.                     \ xdesc.)
  646.         -> #els
  647.         rec? NIF  siz aligned  -> siz  THEN
  648.         #els w,                        \ Add #els to ivar dic entry
  649.         #els wid *                    \ Get indexed length
  650.         rec? NIF  6 +  THEN            \ Add 6 for xdesc length
  651.         ++> clOffs                    \ Add to clOffs
  652.     ELSE            \ Not indexed.
  653.         0 w,
  654.     THEN
  655.     static?
  656.     IF    2 or> flags
  657.     ELSE
  658.         siz ++> clOffs                \ Bump clOffs by non-indexed size of ivar
  659.     THEN
  660.     flags w,
  661.  
  662. (* Now we'll update the class dLen field by whatever we're allocating for this
  663.   ivar - it will then be the offset to the next ivar.  clOffs has the offset
  664.   so far.  In the normal case, this is what goes in dLen.  If we're in
  665.   a union, we MAX it with whatever's already in dLen.  This will leave dLen
  666.   with the longest union element we've reached so far, which will be the final
  667.   value in case we hit the end of the union.
  668.   And if this ivar is static, it will live right where we are in the dic,
  669.   and not in objects of the class, so in this case we leave dLen alone.
  670. *)
  671.     union?
  672.     IF        unionOffs  clOffs  max  -> unionOffs
  673.     ELSE    
  674.         static?
  675.         NIF    clOffs  ^class dfa w!
  676.         THEN
  677.     THEN
  678.  
  679. (* Now we'll check if this ivar is to be static - if so, we'll instantiate
  680.    it right here.
  681. *)
  682.  
  683.     static?  0EXIT
  684.     wid IF  #els  THEN
  685.     iclass  dic-obj
  686. ;
  687.  
  688.  
  689. \                    =================================
  690.  
  691. \                            OBJECT BUILDING
  692.  
  693. \                    =================================
  694.  
  695.  
  696. : CL>LEN ( #els ) { theClass \ wid len -- ( #els ) len2 }
  697.                 \ Gets data length of object given #els and class.
  698.     theClass dlen&xwid  -> wid  -> len
  699.     wid IF    ( #els )  dup 32766 >
  700.         IF  theClass ffa 1+ 0 btest 0= ?error 185  then
  701.          dup  wid *  6 +  len +
  702.     ELSE    len
  703.     THEN  ;
  704.  
  705.  
  706. : MAKE_OBJ  ( #els ) { theClass ^obj \ svHeldMod wid len #els -- }
  707.     0 -> #els
  708.     theClass  ?>classinMod  -> theClass
  709.     heldMod -> svHeldMod  0 -> heldMod        \ So dlen&xwid doesn't unhold
  710.     theClass dlen&xwid  -> wid  -> len
  711.     
  712. \ Now if there's an indexed width, we set up xdesc, the indexed descriptor
  713.     
  714.     wid
  715.     IF    -> #els  len aligned -> len
  716.         ^obj len +  -> ^xdesc        \ It's after the ivars, and aligned
  717.         wid  ^xdesc  w!   #els 1-  ^xdesc 2+  !
  718.         len  12 +
  719.     ELSE    6
  720.     THEN
  721.     
  722. \ Now for the object header.
  723.  
  724.     ^obj obj>  w!
  725.     -6  ^obj 2-  w!
  726.     theClass ?>mainDic
  727.     ^obj 6 -
  728.     false -> relocChk?  reloc!        \ obj addr could be in the heap!
  729.     true  -> relocChk?
  730.     ^obj -> newObject
  731.     theClass ifa displace  0  0  ivSetup
  732.     svHeldMod -> heldMod  ?unholdMod
  733.     
  734. \ Lastly we send classinit: to the object.  Note ivSetup has already
  735. \ sent classinit: to each superclass.
  736.  
  737.     classinit  ;
  738.  
  739.  
  740. :f DIC-OBJ  ( #els ) { theClass \ ^obj -- }
  741.                 \ Builds an object in the dictionary.
  742.     here >obj -> ^obj                \ Where obj data will start
  743.     theClass  cl>len
  744.     8 +  aligned                    \ Required length
  745.     dup room >  ?error 186            \ "Not enough room"
  746.       reserve                            \ Allocate space for object
  747.     theClass  ^obj  make_obj        \ Set up the object
  748.     align-dp  ;f
  749.  
  750.  
  751.     0    value    THECLASS
  752.  
  753.  
  754. :f  BLD        \ ( (#els) -- ) Builds an object.
  755.  
  756.     r>  4-  -> theClass
  757.     cstate
  758.     IF        theClass  ivDef        \ Build an ivar
  759.     ELSE    create_obj            \ Create object header - returns
  760.                                 \  its data address when called
  761.             theClass  dic-obj
  762.     THEN   ;f
  763.  
  764.  
  765. : ]C    true  -> cstate ;        immediate
  766. : C[    false -> cstate ;        immediate
  767.  
  768.  
  769. : HASH,        \ Compiles hashed word for name at here
  770.     @word  hash ,  ;
  771.  
  772.  
  773. \                    ============================
  774.  
  775. \                            :CLASS  etc.
  776.  
  777. \                    ============================
  778.  
  779.  
  780. \ Here we set up some quantities so that we can send messages to SELF
  781. \ or SUPER.  These are treated syntactically as ivars, so to implement
  782. \ them we actually set up dummy ivars SELF and SUPER.
  783.  
  784. \ When we're processing a :CLASS definition, we plug the appropriate
  785. \ addresses into these ivars.  ^SELF is a word defined to return the
  786. \ addr of the dummy ivar SELF, so we can do the plugging.
  787. \ In the case of SUPER, there may be several superclasses, so we have
  788. \ to go through a class descriptor, since that's the only place we look
  789. \ for an n-way (a set of addresses).  So we set the "class" of SUPER
  790. \ to a dummy class SUPCL, which has no ivars or methods (so the search
  791. \ will pass right on by), and plug the superclass pointer of SUPCL to
  792. \ point to the current n-way for the superclasses of the class we're
  793. \ defining.
  794.  
  795.    0    value    (^SELF)
  796.    
  797. : ^SELF  ['] (^self)  displace  ;
  798.  
  799. create    SUPCL                    \ dummy superclass
  800.     classCode  here 2 -  w!
  801.     classMk ,
  802.     0,                            \  methods link - no methods
  803.     0,                            \  ivar link - patched at :CLASS time
  804.  
  805.  
  806. \ META is the super class of Object - top of all inheritance
  807.  
  808. : META    reveal
  809.     [                            \ Note, we're still at the cfa
  810.     drop                        \ Drop the security marker left by colon
  811.     classCode  here 2 -  w!
  812.     classMk ,                    \ class marker goes here
  813.     0,                            \ methods link - none as yet
  814.     0,                            \ ivar link - set to SUPER below
  815.     0,                            \ data len, flags
  816.     0,                            \ super pointer
  817.  
  818. \ Now we set up the SELF and SUPER pseudo-ivars.  We set them up exactly
  819. \ as if they'd been declared as regular ivars in META.  But note we don't
  820. \ set up any fields past the "offset" field, since they're irrelevant.
  821.  
  822. create    SUP                        \ this is so we can tick it at SuperRef below.
  823.  
  824.     here                        \ ready for SELF link below
  825.     hash, SUPER
  826.     0,                            \ empty link
  827.     ' supCl  reloc,                \ ^class is dummy supCl (reloc addr reqd)
  828.     $ FFFE  w,                    \ "offset" FFFE means SUPER
  829.  
  830.  
  831.     here
  832.     hash, SELF
  833.     swap  displ,                \ link
  834.     0,                            \ ^class (gets patched at :CLASS time)
  835.     $ FFFF  w,                    \ "offset" FFFF means SELF
  836.  
  837.  
  838. dup    ' (^self)    displ!
  839.     ' meta ifa    displ!
  840.  
  841.  
  842.     0    value    THISM
  843.     0    value    SUPERM
  844. false    value    1SUPER?
  845.  
  846.  
  847. : :CLASS        immediate
  848.     ?exec  header  classCode w,
  849.     here -> ^class
  850.     0 -> pub/priv  0 -> #1st  0 -> #last
  851.     false -> rec?  false -> union?  false -> static?
  852.     307  ;
  853.  
  854.  
  855. : MERGE_INFO  { ^sup ivlen \ ^wid wid prevWid -- dlen }
  856.     ^sup dlen&xwid  -> wid        \ indexed width of this superclass
  857.     ^sup ffa 1+ c@ 5 and        \ Merge "general" and "indexed" flags with
  858.     ^class ffa 1+  cset            \  what we have already
  859.     wid  0EXIT                    \ If this superclass not indexed, we're done
  860.     
  861. \ This class is indexed - we need to check if prev classes were indexed
  862. \  and make sure the widths are compatible.
  863.  
  864.     ^class dfa 2+  -> ^wid        \ Addr of wid field in class we're building
  865.     ^wid w@  -> prevWid            \ Get previous width
  866.     wid 32767 =                    \ "indexed width" of 32767 really means
  867.     IF                            \  obj_array.
  868.         prevWid                    \ In this case if we already have a width,
  869.         IF        prevWid -> wid    \  we use that,
  870.         ELSE    ivlen  -> wid    \ Otherwise current ivar len becomes the width.
  871.         THEN
  872.     THEN
  873.     prevWid
  874.     NIF     wid  ^wid w!        \ If no prev width, set width & we're done
  875.     ELSE    prevWid wid <>  ?error 88        \ "Incompatible indexed widths"
  876.     THEN  ;
  877.  
  878.  
  879. local    (SUP)   { \ ivlen ^nway ^sup thisLen -- }
  880.  
  881. : NEXT_SUPER    ( cfa -- )
  882.     chkClass  -> ^sup
  883.     ^sup reloc,                        \ Add ^class to n-way
  884.     ^sup ivlen merge_info   -> thisLen
  885.     #sup IF                            \ If this is a subsequent class,
  886.         ivlen aligned  2+  -> ivlen    \  align and allow for ^class offset
  887.     THEN
  888.     thisLen ++> ivlen                \ And add ivar length of new class
  889.     1 ++> #sup  ;
  890.  
  891.  
  892. : SUPERS_LOOP
  893.     BEGIN                        \ Loop over superclasses:
  894.         '                        \ cfa of next item on list
  895.         }or)? IF  drop  EXIT  THEN
  896.         ( cfa )  next_super            \ handle next superclass
  897.         1super?  ?EXIT                \ Yerk has only one superclass
  898.     AGAIN  ;
  899.  
  900.  
  901. :loc  (SUP)
  902.     307 ?pairs                        \ Make sure we're in the right place
  903.     classMk ,  14 reserve            \ Space for class record
  904.     here -> ^nway                    \ n-way for superclasses will
  905.     0 -> ivlen  0 -> #sup            \  start here
  906.     ^nway dup 14 -  displ!            \ Point methods link here
  907.     ^nway dup 10 -  displ!            \ and ivars link
  908.     false -> relocChk?
  909.     supers_loop                        \ Loop over superclasses
  910.     0,                                \ Terminate n-way
  911.     ^nway  ['] supCl  mfa  displ!
  912.     ivlen ^class dfa w!                \ Set total ivar length
  913.     ^class  ^self 8 +  reloc!        \ Store ^class in SELF
  914.     true -> relocChk?
  915.     postpone ]c  ( postpone [ )        \ In a class definition
  916.     308
  917. ;loc
  918.  
  919.  
  920. : SUPER{        false -> 1super?   (sup)  ;        immediate
  921. : SUPER(        postpone super{  ;                immediate
  922.  
  923. : <SUPER    true -> 1super?  (sup)    ;            immediate
  924.             \ For compatibility with Yerk -- only looks for 1 superclass
  925.             
  926.             
  927. : (;CL)
  928.     postpone [   postpone c[
  929.     0 ^self 8 + !  ;
  930.  
  931.  
  932. : ;CLASS
  933.     (;cl)  308 ?defn  ;            immediate
  934.  
  935.  
  936.    0    value    DFRSELID
  937. true    value    SLCTRS?        \ Set false to treat selectors as normal words
  938.                             \  for full ANSI compatibility
  939.  
  940. : SEL?        \ ( addr -- addr b )  True if word at addr is a selector xxx:
  941.     slctrs?  NIF  false  EXIT  THEN
  942.     dup  count tuck  1- + c@  & :  =
  943.     swap 1 >  and  ;
  944.  
  945.  
  946. : GETSELECT            \ Gets a selector from the input stream
  947.     mword
  948.     sel?  not ?error 124
  949.     hash
  950.     0 -> dfrSelID  ;
  951.  
  952.  
  953. ' null    vect    GET1ST&LAST
  954. ' null    vect    DoCall1ST
  955. ' null    vect    DoCallLast
  956.  
  957.  
  958. : M_HEADER  { selID -- }    \ Builds a method header and entry sequence.
  959.                             \ Note: also called from the assembler.
  960.     ^class mfa  selID  hashed-hdr        \ Build header
  961.     pub/priv -1 =  1 and  w,            \ plus private flag (default is public)
  962.     here -> thisM                        \ Remember method cfa
  963.     Mentry  ;                            \ Compile the entry sequence
  964.  
  965.  
  966.  
  967. : :M { \ selID -- }     immediate        \ Start compiling a method.
  968.     true -> method?                    \ Used by Handlers
  969.     ?class  305
  970.     rec? ?error 191                    \ unmatched '{' in ivar list
  971.     0 -> superM
  972.     getSelect -> selID
  973.     10 -> cstate                    \ Means we've read :m, no call_1st yet
  974.     selID ^class 4 (findm)            \ is method already defined?
  975.     IF
  976.         -> superM
  977.         warnings?
  978.         IF    cr  0 -> out
  979.             here count type type# 182             \ "Method redefined"
  980.         THEN
  981.         heldMod 
  982.         NIF  superM ^class > ?error 183  THEN    \ - but if in same class, error
  983.         drop
  984.     THEN
  985.     get1st&last  ?unHoldMod
  986.     selID m_header                        \ Build method header
  987.     #1st #last + IF  thisM 1- 7 bset  THEN
  988.     2 $ 40 + -> obj_base                \ $ 40 indicates A-reg
  989.     0 -> obj_displ                        \ For any inline method calls
  990.     :noname                                \ Start to compile the method
  991.     doCall1st  ;                        \ Compile any Call1st calls first
  992.  
  993.  
  994. : ;M        immediate
  995.     (;)
  996.     #last  IF  true -> method?  doCallLast  defnEnd  false -> method?  THEN
  997.     0 -> #1st  0 -> #last
  998.     305 ?defn  ;
  999.  
  1000.  
  1001. \    ============== Local sections for methods ==============
  1002.  
  1003. \ These function just like regular local sections.  The implementation
  1004. \ is nearly the same.
  1005.  
  1006.     0    value    MLOC_ADDR
  1007.  
  1008.  
  1009. : MLOCAL        \ Starts a local section for methods
  1010.     local?  ?error 93  1 -> local?        \ We change it to the normal -1
  1011.                                         \ as soon as "{" is read.
  1012.     postpone :m
  1013.     postpone [
  1014.     here -> mloc_addr  10 allot        \ Like a forward definition.  We
  1015.                                     \ save the addr to patch and leave
  1016.                                     \ room for the JMP instrn which will
  1017.                                     \ be planted by (patch) below.
  1018.     private  ;
  1019.  
  1020.  
  1021. : :MLOC        immediate
  1022.     public  ?loc  getSelect drop  95
  1023.     here  mloc_addr  (patch)    \ Like :F
  1024.     #PL  IF  PLentry  THEN
  1025.     false -> local?                \ We do this here so any EXITs
  1026.                                 \  tidy everything up properly
  1027.     postpone ]  ;
  1028.  
  1029.  
  1030. : ;MLOC        immediate
  1031.     (;)  95 ?pairs                \ As local? is now false, everything else
  1032.     305 ?defn  ;                \ gets tidied up by (;)
  1033.  
  1034.  
  1035.  
  1036. \    ================   INDEXED, GENERAL etc.   =================
  1037.  
  1038. \ These are words which can appear in a class declaration, in the
  1039. \ position
  1040.  
  1041. \  :class someClass super{ someSuper }   general
  1042.  
  1043. \ They add attributes to the class.
  1044.  
  1045.  
  1046. : INDEXED        \ ( width -- )  Sets a class and its subclasses to indexed
  1047.     ?class  ^class dfa 2+  w!  ;
  1048.  
  1049. : LARGE        \ Sets the "large" option on an indexed class, allowing
  1050.             \ the number of elements to be greater than 32K.
  1051.  
  1052.     ?class  ^class ffa 1+  0 bset  ;
  1053.  
  1054.  
  1055. : GENERAL
  1056.  
  1057. (* Sets the "general" option on a class, which will force an ivar of that class
  1058.    to be a general object with a class pointer (so it can be late-bound to) even
  1059.    if it's within a record.  Normally you should just not put such ivars in a
  1060.    record, but using GENERAL gives a bit of extra security, for classes for which
  1061.    you know that they will definitely be late-bound to.  (An attempt to late-bind
  1062.    to an ivar without a class pointer will give the "not an object" error at run
  1063.    time, which isn't easy to track down.)
  1064.    Note that indexed classes are always general anyway.  Also if there's a message
  1065.    sent to [self] somewhere in one of the methods, we know that the class *must*
  1066.    be general, so in this case we simply set the general attribute.
  1067. *)
  1068.     ?class  ^class ffa 1+  2 bset  ;
  1069.  
  1070.  
  1071. \                    ===========================
  1072.  
  1073. \                            SELECTORS
  1074.  
  1075. \                    ===========================
  1076.  
  1077. \ First, here are the special-purpose things which can follow a selector.
  1078. \ These can't appear in isolation.
  1079.  
  1080. \ We allow ** and [] as synonyms of [ ] to late-bind to whatever is on the
  1081. \ stack.  Note:  [] is used in JForth.
  1082.  
  1083. \ We also allow [self] as a synonym of [ self ]
  1084.  
  1085. : **        83 die  ;        \ "Has no meaning unless preceded by a selector"
  1086. : []        83 die  ;
  1087. : [SELF]    83 die  ;
  1088. : SUPER>    83 die  ;
  1089. : IVAR>        83 die  ;
  1090. : CLASS_AS>    83 die    ;
  1091.  
  1092.  
  1093. : ]        immediate
  1094.     hide  dfrSelID  NIF   postpone ]  EXIT  THEN
  1095.     state
  1096.     IF        251 ?pairs  postpone (defer)  dfrSelID ,
  1097.     ELSE    dfrSelID  send
  1098.     THEN
  1099.     0 -> dfrSelID  ;
  1100.  
  1101.  
  1102. 100        constant    pubIvarTyp        \ &&& temp
  1103. false    value        need_class?
  1104.  
  1105. false    value        implicit_late_bind?        \ true for pre-2.7 auto-late-bind
  1106.                                             \  to locals or values
  1107.  
  1108.  
  1109. (* REFTOKEN ( -- cfa tokenType | -- various type )
  1110.    is called when we've parsed a selector - it determines the type of the
  1111.    following word.
  1112.    
  1113.    The order of checking determines the priority of names.  Up to 2.6 we
  1114.    checked for locals first, but this was a bad idea since a local could
  1115.    have the same name as an object, and implicit late binding to locals
  1116.    was legal.  This wouldn't show up until a crash at run time.  So now we
  1117.    check for temp objects, then ivars, then locals IF implcit_late_bind? is
  1118.    true.
  1119.  
  1120.    "various" will be the cfa of whatever came after the selector, or
  1121.    ( offset ^ivar ) for ivars and temp objects (which are treated as ivars
  1122.    of the class Dummy).
  1123. *)
  1124.  
  1125. : REFTOKEN        \ ( -- cfa tokenType | -- various type )
  1126.  
  1127.     false -> need_class?
  1128.     Mword                                    \ grab next word
  1129.     TOfind    IF  tmpObjTyp    EXIT  THEN        \ check for temp object
  1130.     IVfind    IF  ivarTyp        EXIT  THEN        \ check for ivar
  1131.     
  1132.     implicit_late_bind?
  1133.     IF    Pfind    IF  locTyp    EXIT  THEN        \ check for named parm/locals
  1134.     THEN
  1135.  
  1136.     ( here )  dup thread dup @ +  (find)  0=  ?error 125
  1137.     dup ['] **            =  IF  lbTyp                            EXIT  THEN
  1138.     dup ['] []            =  IF  lbTyp                            EXIT  THEN
  1139.     dup ['] [            =  IF  bktTyp                            EXIT  THEN
  1140.     dup ['] [self]        =  IF  lbSelfTyp                        EXIT  THEN
  1141.     dup ['] super>        =  IF  superTyp                            EXIT  THEN
  1142.     dup ['] ivar>        =  IF  pubIvarTyp                        EXIT  THEN
  1143.     dup ['] class_as>    =  IF  true -> need_class?  classTyp    EXIT  THEN
  1144.     dup hdlr
  1145.     CASE
  1146.         objCode        OF    >obj  objTyp    ENDOF
  1147.         classCode    OF    classTyp        ENDOF
  1148.         -90            OF    classTyp        ENDOF        \ Exported class
  1149.         objPtrCode    OF    objPtrTyp        ENDOF
  1150.         valCode        OF    valTyp            ENDOF
  1151.         wordCode    OF    wordTyp            ENDOF
  1152.         vectCode    OF    wordTyp            ENDOF
  1153.                                 \ Note: here we can treat vectors as words.
  1154.  
  1155.         126 die                        \ "Not an object name"
  1156.     ENDCASE
  1157.  
  1158. \ but if we got wordTyp or valTyp, it's only legal if implicit_late_bind?
  1159. \  is true
  1160.     implicit_late_bind?  ?EXIT        \ all OK - done
  1161.     dup wordTyp =  over valTyp =  or
  1162.     IF  126 die  THEN
  1163. ;
  1164.     
  1165.  
  1166.  
  1167. \ These words handle the binding of a selector to whatever follows it.
  1168.  
  1169. \ FIX_PIVAR does the housekeeping for accessing a public ivar
  1170.  
  1171. : FIX_PIVAR  { ^class in_class? \ offs ^ivar -- cfa offs }
  1172.     pivar ^class 8  (findm)            \ ( offs cfa T  |  F )
  1173.     0= ?error 192                    \ "ivar not found"
  1174.     swap -> offs  8 -  -> ^ivar
  1175.     ^ivar iffa w@                     \ get ivar flags
  1176.     dup 4 and 0=    ?error 193        \ ivar not public
  1177.     2 and                            \ static flag
  1178.     in_class?
  1179.     IF        0=  ?error 197            \ ivar not static
  1180.     ELSE    ?error 195                \ wrong syntax for public static ivar
  1181.     THEN
  1182.     pivSel ^ivar  ivFindM
  1183.   ( cfa loc-offs )
  1184.     in_class?
  1185.     IF    drop ^ivar 26 +
  1186.     ELSE
  1187.         ++> offs   offs
  1188.      THEN
  1189. ;
  1190.  
  1191. \ PUBLIC_STATIC_IVAR_REF handles a message bind to a public static ivar
  1192. \ (done via the  msg: ivar> in_class someClass  syntax)
  1193.  
  1194. : PUBLIC_STATIC_IVAR_REF
  1195.     refToken
  1196.     classTyp <>  ?error 196            \ class name must follow in_class
  1197.     true  fix_pivar
  1198.     bind_to_obj
  1199. ;
  1200.  
  1201.  
  1202. \ OBJREF handles a reference to a normal object.
  1203.  
  1204. : OBJREF  { selID ^obj \ offs -- }
  1205.     selID
  1206.     IF    selID ^obj objFindM swap
  1207.     ELSE            \ it's a public ivar reference in the referenced object
  1208.         ^obj >class false fix_pivar  ^obj +
  1209.     THEN
  1210.      bind_to_obj
  1211. ;
  1212.  
  1213. \ IVARREF handles a reference to an ivar.
  1214.  
  1215. : IVARREF  { selID offs ^ivar \ stat? -- }
  1216.     heldMod  0 -> heldMod                \ Save
  1217.     offs  $ FFFE >=  -> selfRef?        \ If self or super.  Allows private
  1218.                                         \ methods to be found by (findm)
  1219.     selfRef?
  1220.     IF  supers_to_skip -> sups2skip        \ sups2skip is interrogated by (findm).
  1221.                                         \  This must only be done if self or
  1222.                                         \  super is the target.
  1223.     ELSE
  1224.         ^ivar iffa w@ 2 and  -> stat?    \ static ivar?
  1225.     THEN
  1226.  
  1227.     selID
  1228.     IF    selID ^ivar ivFindM
  1229.         0 -> sups2skip  0 -> supers_to_skip
  1230.      ( cfa loc-offs )
  1231.         selfRef?
  1232.         IF        bind_to_self  false -> selfRef?
  1233.         ELSE
  1234.             stat?
  1235.             IF    drop ^ivar 26 +  bind_to_obj
  1236.             ELSE
  1237.                 offs +  bind_to_ivar
  1238.             THEN
  1239.         THEN
  1240.     ELSE
  1241.         ^ivar ^iclass  false  fix_pivar
  1242.         stat?
  1243.         IF    ^ivar 26 + +  bind_to_obj
  1244.         ELSE
  1245.             offs +  bind_to_ivar
  1246.         THEN
  1247.     THEN
  1248.     ?unholdMod  -> heldMod  ;
  1249.  
  1250.  
  1251. \ OBJPTRREF handles a reference to an object pointer.
  1252.  
  1253. : OBJPTRREF  { selID OP-cfa \ ^cl -- }
  1254.     OP-cfa (comp)                    \ Compile a fetch of the OP-cfa,
  1255.                                     \  giving ^obj at run time
  1256.     OP-cfa 4+ @  0= ?error 86        \ "ObjPtr hasn't had a class specified"
  1257.     OP-cfa 4+ @abs  -> ^cl
  1258.     ^cl hdlr -90 =
  1259.     IF                                \ Class is exported
  1260.         ^cl 6 + wdisplace            \ Addr of module
  1261.         compmod =  ?error 84        \ It's the module we're compiling -
  1262.                                     \  this is a no-no, since the ObjPtr
  1263.                                     \  reference will use the OLD module!
  1264.         ^cl  ?>classInMod -> ^cl
  1265.     THEN
  1266.     selID
  1267.     IF    selID ^cl findm swap
  1268.     ELSE
  1269.         ^cl  false  fix_pivar
  1270.     THEN
  1271.     ( cfa offs )  postpone literal  postpone +  bind_to_stk  ;
  1272.  
  1273.  
  1274. \ TMPOBJREF handles a reference to a temp object.
  1275.  
  1276. : TMPOBJREF  { selID offs ^tmpObj \ svHeldMod -- }
  1277.     heldMod -> svHeldMod  0 -> heldMod
  1278.     selID
  1279.     IF    selID ^tmpObj ivFindM
  1280.     ELSE
  1281.         ^tmpObj 8 + @abs  false  fix_pivar
  1282.     THEN
  1283.  ( cfa loc-offs )
  1284.     offs +  bind_to_tmpObj
  1285.     svHeldMod -> heldMod  ;
  1286.  
  1287.  
  1288. \ CLASSREF handles a reference to a class - this means use the object
  1289. \  whose addr is on the stack, but ASSUME it is of the given class
  1290. \  and early bind, without checking.
  1291.  
  1292. : CLASSREF { selID ^class -- }
  1293.     need_class? IF  '  chkClass -> ^class  false -> need_class?  THEN
  1294.     selID
  1295.     IF    selID ^class findm swap
  1296.     ELSE
  1297.         ^class  false  fix_pivar
  1298.     THEN
  1299.     postpone literal  postpone +  bind_to_stk
  1300. ;
  1301.  
  1302.  
  1303. \ SuperRef handles the  msg: super> someSuper  construct.
  1304.  
  1305. : SUPERREF { selID \ ^nway namedClass ^nway' cnt -- }
  1306.     ?class                            \ Must be compiling a class
  1307.     '  -> namedClass                \ get named class xt
  1308.     ^class sfa -> ^nway
  1309.     ^nway -> ^nway'  0 -> cnt
  1310.     BEGIN
  1311.         ^nway' @ 0= ?error 120            \ "superclass" not found
  1312.         ^nway' @abs namedClass =
  1313.     NWHILE
  1314.         1cell ++> ^nway'  1 ++> cnt
  1315.     REPEAT
  1316.     cnt -> supers_to_skip
  1317.     selID  $ FFFE  ['] sup  ivarRef        \ equivalent to msg: super
  1318. ;
  1319.  
  1320. forward COMPREF
  1321.  
  1322. \ PubIvarRef handles the  msg: ivar> someIvar IN someObj  construct, to
  1323. \  send a message directly to a public ivar in an object.
  1324.  
  1325. : PUBIVARREF  { selID \ addr len ^class ^ivar -- }
  1326.     selID -> pivSel
  1327.     mword hash  -> pivar
  1328.     mword count  -> len  -> addr
  1329.     addr len  " IN" s=
  1330.     IF    0                 \ dummy "selID" for compRef (not a legal selector)
  1331.         compRef            \ handle whatever object comes after IN.  The
  1332.                         \  zero selector signals that a public ivar in the
  1333.                         \  indicated object is to be accessed.
  1334.     ELSE
  1335.         addr len " IN_CLASS" s=
  1336.         IF        public_static_ivar_ref
  1337.         ELSE    true ?error 194        \ "wrong syntax for public ivar"
  1338.         THEN
  1339.     THEN
  1340. ;
  1341.  
  1342.  
  1343. \ LBselfRef handles messages to [self] - i.e. late bound to Self.
  1344.  
  1345. : LBSELFREF
  1346.     postpone self  postpone (defer)  ,
  1347.     
  1348.     \ Any class with a late-bound message to self MUST be general.  So if
  1349.     \ we're compling a class (we don't have to be), we'll force it to
  1350.     \ general!
  1351.  
  1352.     cstate IF general THEN  ;
  1353.  
  1354.  
  1355. : COMPDFR    \ (selID cfa -- )
  1356.     (comp)  postpone (defer)  ,  ;
  1357.  
  1358.  
  1359. \ Now here are the main words which compile the selector bindings.
  1360.  
  1361. \ CompRef operates at compile time - it compiles a selector bind.
  1362.  
  1363. :f COMPREF        \ ( selID -- )
  1364.     refToken    \ ( selID addr type ) - addr is ^obj for objects, otherwise
  1365.                 \  the cfa of whatever came after the selector.
  1366.     CASE
  1367.         objTyp        OF  objRef                            ENDOF
  1368.         ivarTyp        OF    ivarRef                            ENDOF
  1369.         objPtrTyp    OF  objPtrRef                        ENDOF
  1370.         tmpObjTyp    OF  tmpObjRef                        ENDOF
  1371.         classTyp    OF    classRef                        ENDOF
  1372.  
  1373. \ These next 3 can only come up if implicit_late_bind? is true:
  1374.         valTyp        OF  compdfr                            ENDOF
  1375.         locTyp        OF  compdfr                            ENDOF
  1376.         wordTyp        OF  compdfr                            ENDOF
  1377.  
  1378.         lbTyp        OF  drop  postpone (defer)  ,        ENDOF
  1379.         lbSelfTyp    OF  drop  LBselfRef                    ENDOF
  1380.         bktTyp        OF  drop  -> dfrSelID  251            ENDOF
  1381.         superTyp    OF    drop  superRef                    ENDOF
  1382.         pubIvarTyp    OF    drop  pubIvarRef                ENDOF
  1383.  
  1384.         82 die                        \ "Selector can't be used on that"
  1385.         
  1386.     ENDCASE  ;f
  1387.  
  1388.  
  1389. (*
  1390. RunRef is the execution mode equivalent - it executes a selector bind.
  1391. We do this simply by compiling it in a buffer then executing it there.
  1392. This replaces the earlier scheme where we had to separately handle each
  1393. case as for compRef - this was a Neon carryover.
  1394.  
  1395. While we're compiling in the buffer, we save the DP on the return stack,
  1396. then restore it before executing what we compiled (since it might do some
  1397. compiling itself).  This isn't long, but it's a bit tricky:
  1398. *)
  1399.  
  1400.     variable    runRefBuf    56 reserve    \ allows 4 nested binds - worst case
  1401.                                         \  14 bytes each
  1402. 0    value        bufPtr
  1403. 0    value        hiDP
  1404.  
  1405. : RUNREF  { selID \ svDP svBufPtr svState -- }
  1406.     DP -> svDP                \ save DP
  1407.     DP hiDP umax -> hiDP    \ so we can reset DP to right place on an error
  1408.  
  1409.     bufPtr NIF  runRefBuf  ELSE  bufPtr  THEN
  1410.     dup -> DP  -> svBufPtr    \ now we'll compile in runRefBuf
  1411.     state -> svState        \ save state
  1412.     postpone ]            \ need compile state so this compilation works properly
  1413.     selID compRef        \ compile the binding
  1414.     postpone (exit)        \ and an exit, so we return to interpretation
  1415.     svState -> state    \ restore state
  1416.     0 -> hiDP            \ don't need it any more and could cause problems
  1417.     ?unholdMod
  1418.     DP -> bufPtr        \ new bufPtr value
  1419.     svDP -> DP            \ restore DP since the code might compile something
  1420.     patches_done        \ we're about to execute what we just compiled
  1421.     svBufPtr execute    \ execute at old bufPtr location
  1422.     svBufPtr -> bufPtr    \ then restore old bufPtr
  1423. ;
  1424.  
  1425.  
  1426. \                ======== Selector support =========
  1427.  
  1428.  
  1429. \ MESSAGE is the handling word invoked by using a selector.
  1430.  
  1431. : MESSAGE        immediate
  1432.     state
  1433.     IF                      \ Compile state
  1434.         compRef                \ Compile the message send
  1435.         ?unHoldMod
  1436.     ELSE
  1437.         runRef                \ Run state - execute object/vector reference.
  1438.                             \ ?unHoldMod is called by ex-method at the
  1439.                             \ end, so we don't need to call it here.
  1440.     THEN  ;
  1441.  
  1442.  
  1443. \ 1stFind lumps together all the special cases we have to look for after
  1444. \ we've parsed an input word, but before we can do a regular dictionary
  1445. \ lookup.  At present these are selectors, named parms/locals, ivars
  1446. \ and local objects.  If we invent more later, they can easily be added.
  1447. \ The vector Ufind is then set to this word so it is called before the
  1448. \ regular dictionary search.  If we succeed here, we return the selector
  1449. \ ID or zero, the cfa of the handling word, and 1 or -1 (this will cause
  1450. \ FIND to exit without doing anything more).  If we fail, we return the
  1451. \ original string address and false.
  1452.  
  1453. : 1stFIND    \ ( str-addr -- selID message-cfa T  |  -- str-addr F )
  1454.     sel?                        \ is it a selector?
  1455.     IF        hash                \ yes - leave selID
  1456.             ['] message  1        \  and cfa of message, and 1 (it's immediate)
  1457.     ELSE    LocFind                \ no - look for the various kinds of local name
  1458.     THEN  ;
  1459.  
  1460.  
  1461. ' 1stFind -> Ufind
  1462.  
  1463.  
  1464. : OBJLEN    \ ( -- objlen )  Computes total data length of current object.
  1465.  
  1466.     ^base (^dlen)  dup w@  swap 2+ w@  ?dup
  1467.     IF  idxBase 4- @ 1+  *  + 4+  THEN   ;
  1468.  
  1469.  
  1470. :f CLASSINIT    newObject classinit: []  ;f
  1471.  
  1472. getSelect classinit:  -> initID
  1473.  
  1474.  
  1475. :f INITIVAR  { boffs infa -- }
  1476.     infa  ^iclass  0EXIT                \ Don't init self or super
  1477.     initID  infa  ivFindM  drop
  1478.     infa  ioffs boffs +  newObject +    \ ( cfa ^data )
  1479.     swap  ex-method  ;f                    \ execute ClassInit:
  1480.  
  1481. forward DUMP
  1482.  
  1483.  
  1484. \ SET_CLASS is a utility word used to patch nucleus objects when their classes
  1485. \ are defined in higher-level files.  Actually it could be used to change the
  1486. \ class of any object, if anyone is silly enough to want to do that.
  1487.  
  1488. \ Usage:  fFcb  ['] file  set_class
  1489.  
  1490. : SET_CLASS  { ^obj theClass -- }
  1491.     theClass  chkClass  ^obj 6 -  reloc!        \ Patch ^class
  1492.     6  ^obj 8 -  w!                    \ Not indexed (yet)
  1493.     -6 ^obj  2-  w!  ;                \ ^class offset
  1494.  
  1495.  
  1496. : CHKSAME        \ ( ^obj -- ^obj )
  1497.         \ A check that two objects are of exactly the
  1498.         \ same class.
  1499.     dup >classCfa  ^base >classCfa  <> ?error 87  ;
  1500.  
  1501.  
  1502. \            ========= Object pointers ==========
  1503.  
  1504. \ Object pointers are low-level objects (like VALUEs) which point to a
  1505. \ normal (high-level) object, and which allow early-bound messages to be
  1506. \ sent to the object by syntactically sending them to the object pointer.
  1507.  
  1508. \ The normal syntax is
  1509.  
  1510. \  ObjPtr  ZZZ    class_is  someClass
  1511.  
  1512. \ Thereafter, any messages sent to zzz are early-bound to the object that
  1513. \ zzz points to at the time the message executes.
  1514.  
  1515. \ If you need to declare the object pointer before the class exists, use
  1516. \ SET_TO_CLASS once the class is defined, thus:
  1517. \
  1518. \ :class  SOMECLASS    super{ object }
  1519. \
  1520. \    ' someOP  set_to_class  someClass
  1521. \
  1522. \    etc.
  1523.  
  1524. : (ToOP)  { ^obj OPcfa \ OPcl -- }
  1525.  
  1526.     ^obj  nilP =                \ If we're storing nil, anything goes
  1527.     NIF    OPcfa 4+ @abs  -> OPcl
  1528.         ^obj 6 - @abs  OPcl  <>
  1529.         IF                      \ Mismatch. We give some useful(?) info.
  1530.             cr  ^obj obj> .id ."  -> "  OPcfa .id
  1531.             87 die
  1532.         THEN
  1533.     THEN
  1534.     ^obj OPcfa !  ;
  1535.  
  1536.  
  1537. :f  ToObjPtr
  1538.     state
  1539.     IF  lit-addr  postpone (toOP)  ELSE  (toOP)  THEN  ;f
  1540.  
  1541.  
  1542. : CLASS_IS    \ ( --< class > )
  1543.     ?exec  '  chkClass  here 4-  reloc!  ;
  1544.  
  1545.  
  1546. : SET_TO_CLASS  { ^objPtr \ ^cl --< class > }
  1547.     '  -> ^cl
  1548.     ^objPtr hdlr -62 <> ?error 85        \ "That isn't an ObjPtr"
  1549.  
  1550.             \ Now if "class" is an imported word, we change the handler code
  1551.             \ to "imported class".  This is normally done when the module
  1552.             \ is compiled, but it may not be yet, since we probably
  1553.             \ want to refer to the ObjPtr in the module.
  1554.  
  1555.     ^cl hdlr -92 = IF  -90 ^cl 2- w!  ELSE  ^cl chkClass drop  THEN
  1556.     ^cl  ^objPtr 4+  reloc!  ;
  1557.  
  1558.  
  1559. \ If you are late-binding in a loop, it can be much faster if you do the bind
  1560. \ just once, then reuse the resulting cfa each time in the loop.  This way
  1561. \ you only have to perform the method search once.  To bind initially and get
  1562. \ the cfa, use
  1563.  
  1564. \  BIND_WITH ( ^obj --<selector> ^obj-modified  cfa )
  1565.  
  1566. \ Usage:  (saveCfa and ^obj-mod are values or locals)
  1567.  
  1568. \    (get object's address)  bind_with someSelector:  -> saveCfa  -> ^obj-mod
  1569.  
  1570. \    (in the loop)  ^obj-mod  saveCfa  ex-method
  1571.  
  1572. \ The use of the modified object address is a bit obscure, and is related to
  1573. \ multiple inheritance.  The method you actually end up binding to may be in
  1574. \ one of the superclasses, and the ivars for that superclass may not start at
  1575. \ the beginning of the object.  The modified object address is the start of
  1576. \ the ivars for the superclass, which is the address the method needs.
  1577.  
  1578. \ Note also that the method may turn out to be in a module, so when you have
  1579. \ finished you should put ?unHoldMod to free up the module.
  1580.  
  1581. : (BWITH)         \ ( ^obj selID -- ^obj-modified  cfa )
  1582.     over  ?>class  findm  >r  +  r>  ;
  1583.  
  1584. : BIND_WITH        \ ( ^obj --<selector> ^obj-modified  cfa )
  1585.     getSelect  postpone literal
  1586.     postpone (bwith)  ;        immediate
  1587.  
  1588.  
  1589. \        ===================================
  1590.  
  1591. :class    OBJECT    super{ meta }
  1592.  
  1593. :m CLASS:    ^base ?>class ?>classinMod  ;m
  1594.  
  1595. :m .ID:        ^base obj>  .id  ;m
  1596.  
  1597. :m .CLASS:    ^base >classCfa  .id  ;m
  1598.  
  1599. :m ADDR:    inline{ obj}
  1600.         ^base  ;m
  1601.  
  1602. :m ABS:        ^base  ;m        \ Included for Neon/Yerk compatibility
  1603.  
  1604. :m LENGTH:    \ ( -- len )  Gets total length of object.
  1605.     objlen  ;m
  1606.  
  1607.  
  1608. (*    Here are two methods which operate between this object and another of
  1609.     the same class.  Note we don't check that the passed-in object is actually
  1610.     of the same class, since it could be a subclass but still be safe to use
  1611.     here.
  1612. *)
  1613.  
  1614. :m COPYTO:    \ ( ^obj -- )  Copies the ivar part of the passed-in object
  1615.             \ to self.
  1616.     ^base  dup (^dlen) w@  aligned_move  ;m
  1617.  
  1618. :m =?:        \ ( ^obj -- b )  Returns true if the ivar part of the passed-in
  1619.             \ object is identical to self.
  1620.     ^base  dup (^dlen) w@  (s=)  ;m
  1621.  
  1622. (*    The following methods need to be defined for all objects.
  1623.     We give them their default definitions here.
  1624. *)
  1625.  
  1626. :m CLASSINIT:  ;m    \ Our standard constructor method.  Called automatically
  1627.                     \ whenever an object is created.
  1628.  
  1629. :m DEEP_CLASSINIT:    \ Also does classinit: on all nested ivars.  Use for
  1630.                     \  totally (re-)initializing an object.
  1631.     ^base -> newObject
  1632.     class: self ifa displace  0  0
  1633.     ivSetup  ?unholdMod  ;m
  1634.  
  1635.  
  1636. (*    RELEASE: is our standard destructor method.  Any objects that
  1637.     allocate heap storage will redefine this appropriately.
  1638.     Our convention is that an object will release ALL its
  1639.     storage when it gets a release: message. Other methods
  1640.     can be provided to partly release storage, as needed.
  1641. *)
  1642.  
  1643. :m RELEASE:    inline{ }  ;m
  1644.  
  1645.  
  1646. :m DUMP:
  1647.     .id: self  ."  class: "  .class: self
  1648.     ^base  objlen  dump  ;m
  1649.  
  1650. :m PRINT:        \ Used for a formatted display, if appropriate.
  1651.                 \ Default is just a dump.
  1652.     dump: self  ;m
  1653.  
  1654. ;class
  1655.  
  1656.  
  1657. \ Bytes is used as the allocation primitive for basic classes
  1658.  
  1659. : BYTES  { numBytes \ svRec? -- }
  1660.     ?class
  1661.     rec? -> svRec?  true -> rec?    \ Don't want an object header here
  1662.     ['] object ivDef
  1663.     numBytes  ^class dfa  w+!
  1664.     svRec? -> rec?  ;
  1665.  
  1666.  
  1667.  
  1668. (*        ===================  Local objects  ======================
  1669.  
  1670. Syntax:
  1671.  
  1672. : aWord  { loc1 loc2 -- }        \ Locals are optional, of course
  1673.     temp
  1674.     {    var        v1
  1675.         int        i1
  1676.         string    s
  1677.     }
  1678.  
  1679.  Or you can use temp{ ...  } if you prefer.
  1680.  
  1681. As the syntax is quite similar to a list of ivars of a class, we actually
  1682. implement the temp objects as though they're the ivars of a dummy class
  1683. (which we uncreatively call Dummy).  This is just a convenience during
  1684. the compilation of a defn with temp objects.  It allows us to define them
  1685. and keep them visible during the compilation of the definition, while mainly
  1686. using existing code for ivar access.  We don't need these ivar dic entries
  1687. once the defn is finished, so we actually put them high in the dictionary
  1688. out of the way of the defn we're compiling.  At the end of the defn,
  1689. we reinitialize Dummy's ivar link ready for next time.
  1690. *)
  1691.  
  1692. getSelect release:            constant    releaseID
  1693.  
  1694.  
  1695. :class DUMMY  super{ object }
  1696. ;class
  1697.  
  1698. ' dummy ifa @    constant    dummyIfa
  1699.  
  1700. : RESETTEMPS
  1701.     dummyIfa  ['] dummy ifa  !
  1702.     0  ['] dummy dfa !                \ clear dlen and xwid
  1703. ;
  1704.     
  1705.     \ Note we don't have to worry about the mfa since Dummy never gets
  1706.     \ its own methods.
  1707.  
  1708.  
  1709. (*
  1710. InitTemps is called when we're compiling the prologue for a definition
  1711. with temp objects.  It compiles a call to make_obj for each object, so
  1712. that they're properly initialized.  Note we can't just call make_obj once
  1713. using class Dummy, since its ivar list is wiped out after each defn
  1714. with temp objects, so at run time it won't have any!  But we don't need
  1715. Dummy at run time anyway - we only need the "ivars" which are the
  1716. temp objects themselves.
  1717. *)
  1718.  
  1719. : 1TEMP  ( ^iclass ioffs -- )
  1720.     locReg +  make_obj  ;
  1721.     
  1722.  
  1723. :f INITTEMPS  { \ infa -- }
  1724.     ['] dummy ifa displace  -> infa
  1725.     BEGIN
  1726.         infa @ 0<
  1727.     WHILE
  1728.         infa ^iclass  lit-addr
  1729.         infa ioffs  postpone literal
  1730.         postpone 1temp
  1731.         infa ^nextivar  -> infa
  1732.     REPEAT  ;f
  1733.  
  1734. (*
  1735. ReleaseTemps is called back from Handlers when it's compiling an exit.
  1736. It compiles a release: xxx for all temp objects.  Because of the way
  1737. we've defined release: in class Object, for simple objects no code will
  1738. actually be generated.  
  1739.  
  1740. Note we mustn't call resetTemps here since this might be an EXIT, not
  1741. the final semicolon.  We leave calling resetTemps till a new temp{ comes
  1742. up.
  1743. *)
  1744.  
  1745. : RELEASETEMPS  { \ infa -- }
  1746.     ['] dummy ifa displace  -> infa
  1747.     BEGIN
  1748.         infa @ 0<
  1749.     WHILE
  1750.         infa  ^iclass  0EXIT            \ shouldn't happen, actually
  1751.         releaseID  infa  ivFindM drop
  1752.         infa ioffs bind_to_tmpObj        \ compile release:
  1753.         infa ^nextivar  -> infa
  1754.     REPEAT
  1755. ;
  1756.  
  1757.  
  1758. : }TEMP
  1759.     130 ?pairs
  1760.     ['] } !                                \ restore old action for "}"
  1761.     -> ^class  -> state  -> cstate  -> DP    \ restore other things
  1762.     tmpObjs dlen 8 +  -> frameSize        \ work out frame size
  1763.     local? NIF                            \ compile prologue unless we're in
  1764.         PLentry  initTemps                \  a local section (then it gets done
  1765.     THEN                                \  by :LOC)
  1766.     ['] releaseTemps -> relTmps            \ for Handlers callback at exit time
  1767. ;
  1768.  
  1769.  
  1770. : TEMP{        immediate
  1771.  
  1772. (*    First we have to allocate an internal local variable as a frame pointer.
  1773.     There are 4 situations.  There may or may not already be locals, and
  1774.     we may or may not be in a local section.  Note we can be in a local
  1775.     section even if there aren't already locals, since the purpose of the
  1776.     local section might be just to establish a section for these temp objects.
  1777.  
  1778.     If there are already locals, we just add another.  If we're not in a
  1779.     local section we need to recompile the entry sequence (done by PLentry)
  1780.     since the number of regs to be saved and set up is different.  But if
  1781.     we're in a local section, we don't have to recompile since we haven't
  1782.     called PLentry yet, so we just add the extra local.  If there aren't any
  1783.     locals already, we just call initLocs which sets them up, before adding
  1784.     the new one.
  1785. *)
  1786.     resetTemps
  1787.     #PL IF
  1788.         local?    NIF  PLentry_addr -> DP  THEN
  1789.     ELSE
  1790.         initLocs                \ No locs before, so set up for them now
  1791.     THEN
  1792.     local? IF  -1 -> local?  THEN    \ If in a local section, setting local?
  1793.                                     \ to -1 means we've defined the locals
  1794.                                     \ so can't do it again
  1795.     " x " here place  here addToParmList
  1796.  
  1797. (*    next we save DP and move halfway up in the free dic space - we'll put
  1798.     the "ivar dic entries" for the temp objs there - we don't need them
  1799.     after the defn is compiled.
  1800. *)
  1801.     here            room 2/ ++> DP  align-dp
  1802.     cstate            true -> cstate
  1803.     state
  1804.     ^class
  1805.     ['] } @                        \ save old action for "}"
  1806.     ['] }temp  -> }                \ "}" will now be same as }temp
  1807.     130                            \ for ?pairs
  1808.  
  1809.     ['] dummy dup    -> ^class    \ local objs will look like ivars of Dummy
  1810.                     -> tmpObjs    \ this will enable finding them
  1811.     
  1812.  
  1813.  
  1814.     postpone [                    \ stop compiling
  1815. ;
  1816.  
  1817.                             
  1818. : TEMP        gobble{  postpone temp{  ;        immediate
  1819.  
  1820.  
  1821. (*        =================  Records and unions  ====================
  1822.  
  1823. Syntax:
  1824.  
  1825.     record <name>        \ The name is optional
  1826.    {    var        v1
  1827.         int        i1
  1828.         string    s
  1829.    }
  1830.    
  1831.        union <name>        \ The name is optional
  1832.    {    var        v1
  1833.         int        i1
  1834.         string    s
  1835.    }
  1836.  
  1837.  
  1838. Or you can use record{ ...  } or union{ ... } if you prefer, if it's
  1839. unnamed.  The similarity of syntax to temp objects is quite deliberate.
  1840. But any similarity to Your Favorite Language is entirely accidental.  Well
  1841. actually it's not, but I think this syntax is as good as any, and probably
  1842. more readable for folks coming from C-land.
  1843.  
  1844. unions can be nested within records and vice versa.
  1845.  
  1846. *)
  1847.  
  1848.  
  1849. : SVREC        rec?  union?  unionOffs  ;
  1850. : RSTREC    -> unionOffs  -> union?  -> rec?  ;
  1851.  
  1852. : ?HANDLE_NAME  { \ sv_>in sv_^class sv_rec? -- }
  1853.     >in @ -> sv_>in ^class -> sv_^class  rec? -> sv_rec?
  1854.     Mword  count  " {" s=
  1855.     NIF                            \ we've got a name for the record
  1856.         true -> rec?            \ must do this before defining the name "object"
  1857.         sv_>in  >in !
  1858.         ['] object  ivDef
  1859.         sv_rec? -> rec?  sv_^class -> ^class
  1860.         gobble{                    \ "{" must follow
  1861.     THEN
  1862. ;
  1863.  
  1864.  
  1865. : }RECORD
  1866.     131 ?pairs  rstRec
  1867.     ['] } 4+ !                    \ restore old action for "}"
  1868.     ( false -> rec? )  ;
  1869.  
  1870.  
  1871. : RECORD{
  1872.     ?class                        \ must be compiling a class
  1873.     ['] } 4+ @                    \ save old action for "}"
  1874.     ['] }record  -> }            \ "}" will now be same as }record
  1875.     svRec                        \ save parameters for any existing record/union
  1876.     131                            \ for ?pairs
  1877.     true -> rec?  false -> union?  ;
  1878.  
  1879. : RECORD
  1880.     ?handle_name
  1881.     record{  ;
  1882.  
  1883.  
  1884. : }UNION
  1885.     132 ?pairs
  1886.     unionOffs  ^class dfa w!    
  1887.     rstRec
  1888.     ['] } 4+ !  ;                \ restore old action for "}"
  1889.  
  1890. : UNION{
  1891.     ?class                        \ must be compiling a class
  1892.     ['] } 4+ @                    \ save old action for "}"
  1893.     ['] }union  -> }            \ "}" will now be same as }union
  1894.     svRec                        \ save record/union parameters
  1895.     132                            \ for ?pairs
  1896.     true -> rec?  true -> union?
  1897.     ^class dfa w@ -> unionOffs  ;
  1898.  
  1899.  
  1900. : UNION
  1901.     ?handle_name
  1902.     union{  ;
  1903.  
  1904.  
  1905. (*        =================  Static ivars ====================
  1906.  
  1907. Syntax:
  1908.  
  1909.     static
  1910.    {    var        v1
  1911.         int        i1
  1912.         string    s
  1913.    }
  1914.  
  1915. Or you can use  static{ ...  } if you prefer.
  1916.  
  1917. These are like static class variables in C++ - they belong to the class,
  1918. not the object, and thus are shared by all objects of the class.  We
  1919. allocate each ivar in the dictionary right after its ivar header.
  1920. *)
  1921.  
  1922. : }STATIC
  1923.     133 ?pairs
  1924.     ['] } 4+ !                    \ restore old action for "}"
  1925.     false -> static?  ;
  1926.  
  1927.  
  1928. : STATIC{
  1929.     ?class                        \ must be compiling a class
  1930.     ['] } 4+ @                    \ save old action for "}"
  1931.     ['] }static  -> }            \ "}" will now be same as }static
  1932.     133                            \ for ?pairs
  1933.     true -> static?  ;
  1934.  
  1935. : STATIC
  1936.     gobble{  static{  ;
  1937.  
  1938.  
  1939. \            ==========================================
  1940.  
  1941. \ CL1 is our first cleanup word - called on an abort.  Resets things
  1942. \  to normal.  Later cleanup words do their special stuff, then call CL1.
  1943.  
  1944. : CL1
  1945.     (;cl)  clrComp  ['] (}) -> }
  1946.     resetTemps  false -> rec?  false -> union?
  1947.     0 -> extraFind
  1948.     0 -> bufPtr
  1949.     DP hiDP umax  -> DP
  1950.     false -> case_in_names?
  1951. ;
  1952.  
  1953. ' cl1  -> abortVec
  1954.  
  1955.  
  1956. load Struct
  1957.  
  1958. \            ==========================================
  1959.  
  1960. (* Normally we don't get here.  In order to do various tests on classes,
  1961.  we comment out the  <" Struct  and run various parts of the torture test
  1962.  stuff following.
  1963. *)
  1964.  
  1965. +echo
  1966.  
  1967. :class    VAR    super{ object }
  1968.  
  1969.     4 bytes data
  1970.  
  1971. :m CLEAR:
  1972.     inline{ 0 obj !}
  1973.     0 ^base !  ;m
  1974.  
  1975. :m GET:
  1976.     inline{ obj @}
  1977.     ^base @  ;m
  1978.  
  1979. :m PUT:
  1980.     inline{ obj !}
  1981.     ^base !  ;m
  1982.  
  1983. :m GETT:    ^base @  ;m
  1984.     
  1985. :m PUTT:    ^base !  ;m
  1986.  
  1987. :m +:
  1988.     inline{ obj +!}
  1989.     ^base +!  ;m
  1990. :m -:
  1991.     inline{ obj -!}
  1992.     ^base -!  ;m
  1993. :m ->:
  1994.     inline{ @ obj !}
  1995.     chksame  get: var  put: self  ;m
  1996.  
  1997. :m TEST:        db  ;m
  1998.  
  1999. mlocal LOCTEST:  { aa \ bb cc -- }
  2000.  
  2001. :m AAA:    aa -> bb ;m
  2002.  
  2003. :mloc  LOCTEST:
  2004.     db  aaa: self  cc -> bb  1234 drop ;mloc
  2005.  
  2006.  
  2007. :m  PRINT:
  2008.     ^base @  .  ;m
  2009.  
  2010. :m CLASSINIT:    $ 123  put: self  ;m
  2011.  
  2012. ;class
  2013.  
  2014. :class    BYTE    super(  object  )
  2015.  
  2016.     1 bytes data
  2017.  
  2018. :m CLEAR:
  2019.     inline{ 0 obj c!}
  2020.     0 ^base c!  ;m
  2021.  
  2022. :m GET:
  2023.     inline{ obj c@x}
  2024.     ^base c@x  ;m
  2025.  
  2026. :m UGET:
  2027.     inline{ obj c@}
  2028.     ^base c@  ;m
  2029.  
  2030. :m PUT:
  2031.     inline{ obj c!}
  2032.     ^base c!  ;m
  2033.  
  2034. :m ->:
  2035.     inline{ c@ obj c!}
  2036.     chksame  c@  put: self  ;m
  2037.  
  2038. :m PRINT:
  2039.     ^base c@  .        ;m
  2040.  
  2041. :m CLASSINIT:    9 put: self  ;m
  2042.  
  2043. ;class
  2044.  
  2045. key!
  2046.  
  2047. :class    BOOL    super(  byte  )
  2048.  
  2049. :m GET:
  2050.     inline{ obj c@x}
  2051.     ^base c@x  ;m
  2052.  
  2053. :m PUT:
  2054.     inline{ 0<> obj c!}
  2055.     0<>  ^base c!  ;m
  2056.  
  2057. :m SET:
  2058.     inline{ true obj c!}
  2059.     true ^base c!  ;m
  2060.  
  2061. :m PRINT:
  2062.     get: self  IF  ." true"  ELSE  ." false"  THEN  ;m
  2063.  
  2064. :m CLASSINIT:    clear: self  ;m
  2065.  
  2066. ;class
  2067.  
  2068.  
  2069. :class    BARRAY  super{ object }  1 indexed
  2070.  
  2071. :m  AT:        \ ( index -- n )
  2072.     inline{ ix c@}
  2073.     ^elem1  c@  ;m
  2074.  
  2075. :m  TO:        \ ( n index -- )
  2076.     inline{ ix c!}
  2077.     ^elem1  c!  ;m
  2078.  
  2079.  
  2080. :m ^ELEM:    \ ( index -- addr )
  2081.     inline{ ix}
  2082.     ^elem1  ;m
  2083.  
  2084. :m FILL:    \ ( value -- )  Fills all elements with value.
  2085.     idxbase  limit 2*  bounds
  2086.     ?DO  dup  i c!  LOOP  drop  ;m
  2087.  
  2088. :m WIDTH:    1  ;m        \ Faster than the default in Object
  2089.  
  2090. :m GETELEM:    \ ( addr -- n )  Fetches one element at addr
  2091.     c@x  ;m
  2092.  
  2093. ;class
  2094.  
  2095.  
  2096. \ Testing static ivars
  2097.  
  2098. :class SIVTEST  super{ var }
  2099. public
  2100. static
  2101. {    var        V1
  2102.     bool    B1
  2103.     byte    B2
  2104. 10    barray    BB
  2105. }
  2106.     bool    BLOC
  2107.     var        VLOC
  2108.     
  2109. :m QQ:    db  get: v1  get: b1  get: b2 4 at: bb
  2110.         get: vloc  ;m
  2111.  
  2112. ;class
  2113.  
  2114. sivtest zzz
  2115. sivtest sss
  2116. objPtr myop  class_is sivtest
  2117.  
  2118. : QQQ    db    get: ivar> b2 in_class sivtest
  2119.             get: ivar> v1 in_class sivtest
  2120.             sss get: ivar> bloc in class_as> sivtest  ;
  2121.  
  2122. key!
  2123.  
  2124. :class HAHA  super{ object }
  2125.  
  2126.     sivtest    IVsss
  2127.     
  2128. :m QQ:    db  get: ivar> vloc IN ivsss  ;m
  2129. ;class
  2130.  
  2131. haha hh
  2132.  
  2133. : WWW  temp { sivtest mysiv }
  2134. db    get: ivar> vloc IN mysiv
  2135.     mysiv -> myop
  2136.     get: ivar> vloc IN myop  ;
  2137.  
  2138. +echo
  2139. \ Testing record{
  2140.  
  2141. :class VAR+ super{ var }
  2142.  
  2143. :m QQ:    db
  2144.         get: [self]        \ should make class general
  2145.         get: [ self ]
  2146.         db
  2147. ;m
  2148.  
  2149. ;class
  2150.  
  2151. var+ VVV
  2152. key!
  2153.  
  2154. +echo
  2155. :class RECTEST super{ object }
  2156.     var    vv
  2157.     record RR
  2158.     {        var        v1
  2159.             bool    b1
  2160.         3    barray  bbb
  2161.             byte    dummyToMakeAddrOdd
  2162.         union {    byte    b2
  2163.                 var        v2
  2164.                 record    {    byte bb1
  2165.                             byte bb2    }
  2166.             }
  2167.             var        v3
  2168.     }
  2169.     
  2170. :m TEST:
  2171.     db  get: v1  put: b1  get: b2  get: v2  get: bb1  get: bb2  get: v3
  2172. ;m
  2173. ;class
  2174.  
  2175. recTest rrr
  2176. test: rrr
  2177.  
  2178.  
  2179. \ Testing temp objects
  2180.  
  2181. : q db
  2182. temp
  2183. {    var    v1
  2184.      var    v2
  2185. }temp
  2186.     v1 v2
  2187.     get: v1  get: v2 db ;
  2188.  
  2189.  
  2190.  
  2191. :class INT  super( object )
  2192.  
  2193.     2    bytes    data
  2194.  
  2195. :m CLEAR:
  2196.     inline{  0 obj !  }
  2197.     0 ^base !  ;m
  2198.  
  2199. :m UGET:
  2200.     inline{  obj w@  }
  2201.     ^base w@  ;m
  2202.  
  2203. :m GET:
  2204.     inline{  obj w@x  }
  2205.     ^base w@x  ;m
  2206.  
  2207. :m IPUT:    ^base w!  ;m
  2208.  
  2209. :m DISP:
  2210.     inline{  obj 2+ @  }  ;m
  2211.  
  2212. :m PUT:
  2213.     inline{  obj w!  }
  2214.     ^base  w!  ;m
  2215.  
  2216. :m MOVE:
  2217.     inline{  obj 4+ w@  obj w!  }  ;m
  2218.  
  2219.  
  2220. :m +:    inline{  obj w+!  }
  2221.     ^base  w+!  ;m
  2222.  
  2223. :m ->:
  2224.     inline{  w@ obj w!  }
  2225.     db  chksame  1234 drop  get: int  put: self  ;m
  2226.  
  2227. :m ++>:
  2228.     inline{  w@ obj w+!  }
  2229.     db  chksame  uget: int  +: self  ;m
  2230.  
  2231. :m .ID:    ." haha"  ;m
  2232.  
  2233. :m TEST:
  2234.     1234 drop  .id: super  ;m
  2235.  
  2236. :m CLASSINIT:    db  $ 456 put: self  ;m
  2237.  
  2238. ;class
  2239.  
  2240.  
  2241. :class CC  super{ byte int var bool }
  2242.  
  2243. :m TEST:
  2244.     db  uget: self        \ offs should be 0
  2245.     +: self                \ offs should be 4
  2246.     set: self  ;m        \ offs should be A
  2247.  
  2248. :m TEST1:
  2249.     db  set: self
  2250.     get: super> bool    \ should get -1
  2251.     get: super
  2252. ;m
  2253.     
  2254. :m classinit:  db  ;m
  2255.  
  2256. ;class
  2257.  
  2258. cc CCC
  2259.  
  2260.  
  2261. :class STRANGE  super{ object }
  2262.     var VV
  2263.     byte BB
  2264. :m GET:  get: vv  get: bb  ;m
  2265. :m PUT:  put: bb  put: vv  ;m
  2266.  
  2267. ;class
  2268.  
  2269.  
  2270. :class    ARRAY    super(  object  )    4 indexed
  2271.  
  2272. \ 8 bytes data        \ Comment out to check collapsing of embedded objs
  2273.  
  2274. :m ^ELEM:    \ ( index -- addr )
  2275.     ^elem4  ;m
  2276.  
  2277. :m QQQ:    inline{ ix }  ;m
  2278.  
  2279. :m  AT:        \ ( index -- n )
  2280.     inline{ ix @ }
  2281.     ^elem4  @  ;m
  2282.  
  2283. :m  ATT:    ^elem  @  ;m        \ As for AT:, but not inline
  2284.                 \  and uses unoptimized ^elem
  2285.  
  2286. :m  TO:        \ ( n index -- )
  2287.     inline{  ix !  }
  2288.     ^elem4  !  ;m
  2289.  
  2290. :m  +TO:        \ ( n index -- )
  2291.     inline{ ix +! }
  2292.     ^elem4  +!  ;m
  2293.  
  2294. :m -TO:        \ ( n index -- )
  2295.     inline{ ix -! }
  2296.     ^elem4  -!  ;m
  2297.  
  2298. :m FILL:        \ ( value -- )  Fills all elements with value.
  2299.     idxbase  limit 4*  bounds
  2300.     DO  dup  i !  4 +LOOP  drop  ;m
  2301.  
  2302. :m EXEC:        \ ( index -- )  execute the cfa, by jumping there.
  2303.     inline{ ix ex}
  2304.     ^elem: self  execute  ;m
  2305.  
  2306. :m TEST:
  2307.     exec: self  ;m
  2308.  
  2309. :m ATEST:
  2310.     1 at: self  ;m
  2311.  
  2312. ;class
  2313.  
  2314. var VV
  2315.  
  2316. :class XXX super( object )
  2317.     var    VV1
  2318.     var    VV2
  2319. 3    array    AA
  2320.  
  2321. :m TEST:     inline{ 9 putt: vv2 get: vv2 at: aa}  get: vv2 ;m
  2322. :m TESTT:    db  2 at: aa  get: vv1  get: vv2  ;m
  2323. :m ZZ:        inline{ get: vv2 get: vv}  get: vv2  ;m
  2324.  
  2325. :m  CLASSINIT:        3 0 do  $ 777  i  to: aa   loop  ;m
  2326. ;class
  2327.  
  2328. :class    YYY    super{ xxx }
  2329. ;class
  2330.  
  2331. :class    ZZZ    super{ object }
  2332.     xxx    X1
  2333.     yyy    Y1
  2334. :m TEST: db  ;m
  2335. ;class
  2336. zzz    Z1
  2337.  
  2338. :class    QQQ  super( object )
  2339.     xxx    XXX1
  2340.     xxx    XXX2
  2341. :m TEST:  zz: xxx1  zz: xxx2  zz: xxx1  ;m
  2342. ;class
  2343.  
  2344. objPtr OO  class_is  xxx
  2345.  
  2346. xxx xxxx
  2347. qqq qqqq
  2348. xxxx -> oo
  2349.  
  2350. :class BLOGGS  super( object )
  2351.     var VV
  2352.     4    array AA
  2353. :m TEST:  db    2 +  i -  at: aa ;m
  2354. ;class
  2355.  
  2356. bloggs BB
  2357.  
  2358.  
  2359.  
  2360. :class MULT    super( var int array )
  2361.  
  2362. :m MTEST:    uget: super  999 1 to: self  ;m
  2363. :m MAT:        at: self  ;m
  2364. ;class
  2365.  
  2366. objPtr    OO    class_is mult
  2367. objPtr    OOO    class_is int
  2368.  
  2369. :class IVXX    super( object )
  2370.     10 bytes data2
  2371.     int    i1
  2372.     int    i2
  2373.     130 bytes qqqq        \ Include to check >128 distance
  2374.                 \  index addressing of array qwert
  2375.     9 array qwert
  2376.  
  2377. :m ITEST:
  2378.     get: i1  uget: i2  66 put: i2
  2379.     99 3 to: qwert  1234 drop  3 at: qwert
  2380.     addr: i2  ['] ooo !  ;m
  2381.  
  2382. :m GETQWERT:
  2383.     addr: qwert  ;m
  2384. ;class
  2385.  
  2386. int ii
  2387. 3 mult    mm
  2388. ivxx    iv
  2389.  
  2390. mm -> oo
  2391.  
  2392. itest: iv  . . .
  2393. mtest: mm  .
  2394. 88 iput: mm        \ Note: get: mm will bind to the var, but uget: mm
  2395.             \ will bind to the int and give 88.
  2396.  
  2397. \ A further test - Doug H found this bug:
  2398.  
  2399. :class  POINT    super{ object }
  2400.     int    Y        \ Vertical coordinate
  2401.     int    X        \ Horizontal  coordinate
  2402. ;class
  2403.  
  2404.  
  2405. :class  RECT  super{ object }
  2406.     point    TOPL
  2407.     point    BOTR
  2408. ;class
  2409.  
  2410. :class test1 super{ object }
  2411.  
  2412.     20 array a
  2413.  
  2414. :m classinit:
  2415.     55 0 to: a ;m
  2416.  
  2417. :m to:  to: a ;m
  2418.  
  2419. :m at:  at: a ;m
  2420.  
  2421. ;class
  2422.  
  2423. :class test3 super{ rect test1 }
  2424. :m classinit:
  2425.     [ 1 -> supers_to_skip ]  classinit: super
  2426. ;m
  2427. ;class
  2428.  
  2429. test3 t3
  2430.  
  2431.  
  2432. : q            db  getqwert: iv  3 swap at: **  ;        \ Should give 99
  2433. : qq        db 1 at: mm ;                            \ Should give 999
  2434. : qqq        db 1 mat: mm  ;                            \ Should give 999
  2435. : qqqq        db 1 mm at: mult  ;                        \ Should give 999
  2436. : z            db 1 mm at: **  ;                        \ Should give 999
  2437. : zz        db 1 mm at: array ;                        \ Should fail
  2438. : y            db 1 at: oo   ;                            \ Should give 999
  2439. : yy        db 1 mat: oo  ;                            \ Should give 999
  2440. : yyy        db uget: mm  ;                            \ Should optimize & give 88
  2441. : yyyy        db addr: mm  addr: oo  ;                \ Both numbers shd be same
  2442. : yyyyy        db uget: ooo  ;                            \ Should give 66
  2443. : yyyyyy    db  0 at: t3  ;                            \ Should give 55
  2444.  
  2445.  
  2446. : ?CHK    <> abort" check FAILED!!!"  ;
  2447.  
  2448. q         99    ?chk
  2449. qq         999    ?chk
  2450. qqq     999    ?chk
  2451. qqqq     999 ?chk
  2452. z         999    ?chk
  2453. y         999    ?chk
  2454. yy         999    ?chk
  2455. yyy     88    ?chk
  2456. yyyy        ?chk
  2457. yyyyy     66    ?chk
  2458. yyyyyy    55    ?chk
  2459.  
  2460. \ torture tests WORKED!  INCREDIBLE!!  CONGRATULATIONS!!!
  2461. \ (but remember to check that ZZ gives a "can't use indexed method" error)
  2462. key!
  2463.  
  2464. :class MULTX super( mult )
  2465. :m ntest:  db  444 1 to: super  ;m
  2466. ;class
  2467. 4 multx MX
  2468.  
  2469. \ ivar clash test
  2470.  
  2471. :class CLASH super( object )
  2472.  
  2473. 2 array A1
  2474. 3 array A2
  2475.  
  2476. :m TEST: db 77 1 to: a1  66 0 to: a2  1 at: a1  ;m    \ Shd give 77
  2477.  
  2478. ;class
  2479.  
  2480. clash CC
  2481.